<template>
  <div class="tag-editor gap-col-5">
    <label class="font-size-12 font-weight-400 line-height-120">{{ $t('info.tag') }}</label>
    <div class="tags bg-surface gap-row-8" :class="{ error: !!errMsg }" @click.self="inputEl.focus()">
      <transition-group name="tags">
        <div v-for="tag in tags" class="tag gap-row-8" :key="tag">
          <span class="font-size-14 font-weight-400 line-height-140 text-primary">{{ tag }}</span>
          <Icon name="closeActive" class="pointer" @click="delTag(tag)"></Icon>
        </div>
      </transition-group>
      <div class="input">
        <input
          v-model="input"
          ref="inputEl"
          class="font-size-14 font-weight-500 line-height-140"
          type="text"
          :placeholder="inputPlaceholder"
          @keyup="onInput"
          @paste="onPaste"
          @focus="focus = true"
          @blur="focus = false"
        />
        <div v-if="focus || input" class="tag gap-row-8">
          <span class="font-size-14 font-weight-400 line-height-140">{{ input }}</span>
          <Icon name="closeActive" class="pointer" @click="input = ''"></Icon>
        </div>
      </div>
    </div>
    <div v-if="errMsg" class="err-msg font-size-12 font-weight-400 line-height-120 text-primary-x text-right">
      {{ errMsg }}
    </div>
    <div class="cached-tags gap-row-8">
      <transition-group name="tags">
        <div v-for="cachedTag in cachedTags" class="tag gap-row-8" :key="cachedTag">
          <span class="font-size-14 font-weight-400 line-height-140 pointer" @click="addTag(cachedTag)">
            {{ cachedTag }}
          </span>
          <Icon name="close" class="pointer" @click="delCachedTag(cachedTag)"></Icon>
        </div>
      </transition-group>
    </div>
  </div>
</template>

<script setup>
import { computed, ref, watch } from 'vue'
import { useLocalStorage } from '@vueuse/core'
import { usePopupMessageStore } from '@/store/popup-message'
import { $t } from '@/i18n'
import { LOCAL_STORAGE_KEYS } from '@/constant'

const props = defineProps({
  modelValue: { type: Array, required: true },
  errMsg: { type: String, default: '' },
})

const emits = defineEmits(['update:modelValue'])

const { open } = usePopupMessageStore()

const tags = computed({
  get() {
    return props.modelValue
  },
  set(v) {
    emits('update:modelValue', v)
  },
})

// ['壞壞', '臭臭', '色色']
const cachedTags = useLocalStorage(LOCAL_STORAGE_KEYS.FEED_TAGS, [])

const input = ref('')
const focus = ref(false)
const inputPlaceholder = computed(() => (focus.value ? '' : $t('placeholder.splitByComma')))
let readyCloseForBackspace = true
function onInput(evt) {
  const key = evt.key.toLowerCase()
  switch (key) {
    case 'backspace':
      if (input.value === '') {
        if (readyCloseForBackspace) {
          inputEl.value.blur()
        } else {
          readyCloseForBackspace = true
        }
      }
      break

    case 'enter':
      if (addTag(input.value)) {
        input.value = ''
      }
      break

    case '#':
    case ',': {
      const v = input.value.substring(0, input.value.length - 1)
      if (stringWidth(v) < TAG_NAME_LESS) {
        input.value = v
      } else {
        if (addTag(v)) {
          input.value = ''
        }
      }
      break
    }
  }

  if (key !== 'backspace') {
    readyCloseForBackspace = false
  }
}
function onPaste(evt) {
  const pasteValue = evt.clipboardData.getData('text/plain')
  pasteValue
    .trim()
    .split(',')
    .filter((s) => s)
    .flatMap((s) =>
      s
        .trim()
        .split('#')
        .filter((s) => s),
    )
    .forEach((tag) => addTag(tag.trim()))

  const stop = watch(input, (v) => {
    if (v === pasteValue) {
      input.value = ''
      stop()
    }
  })
}
const inputEl = ref(null)

const TAG_COUNT_LIMIT = 10
const TAG_NAME_LESS = 2
const TAG_NAME_MORE = 20
function addTag(name) {
  // 最多十個
  if (tags.value.length === TAG_COUNT_LIMIT) {
    open($t('info.publishTagLimitCount', { count: TAG_COUNT_LIMIT }))
    return false
  }

  // 長度不符合
  if (stringWidth(name) < TAG_NAME_LESS) {
    open($t('info.publishTagNameLess'))
    return false
  }
  if (stringWidth(name) > TAG_NAME_MORE) {
    open($t('info.publishTagNameMore'))
    return false
  }

  const tag = findTagFromCache(name)

  // 已存在
  if (tags.value.findIndex((tag) => tag === name) !== -1) {
    return true
  }

  tags.value.push(tag)
  return true
}

function delTag(delTag) {
  tags.value = tags.value.filter((tag) => tag !== delTag)
}

function delCachedTag(delTag) {
  cachedTags.value = cachedTags.value.filter((tag) => tag !== delTag)
}

function findTagFromCache(name) {
  const findedIndex = cachedTags.value.findIndex((cachedTag) => cachedTag === name)

  // 找到的話將該 tag 排至第一個後直接回傳
  if (findedIndex > -1) {
    const findedTag = cachedTags.value.splice(findedIndex, 1)[0]
    cachedTags.value.unshift(findedTag)
    return findedTag
  }

  // 沒在 cache 裡找到
  // cache 已存在十個要把最舊那個刪了
  if (cachedTags.value.length === TAG_COUNT_LIMIT) {
    cachedTags.value.pop()
  }

  cachedTags.value.unshift(name)

  return name
}

function stringWidth(str) {
  let width = 0
  for (let i = 0; i < str.length; i++) {
    // eslint-disable-next-line no-control-regex
    width += /[^\x00-\x7F]/.test(str.charAt(i)) ? 2 : 1
  }
  return width
}
</script>

<style lang="scss" scoped>
.tag-editor {
  margin-bottom: 0.5rem;
  display: flex;
  flex-direction: column;

  .tags {
    height: 8.25rem;
    padding: 1rem;
    border-radius: 0.875rem;
    overflow: auto;
    align-content: flex-start; // flex-wrap 變成 multiline 的對齊要用這個
    .tag {
      border: 0.125rem solid rgb(var(--v-theme-primary));
    }

    &.error {
      border: 0.0625rem solid rgb(var(--v-theme-primary-x));
      background: linear-gradient(0deg, rgba(235, 0, 27, 0.1) 0%, rgba(235, 0, 27, 0.1) 100%),
        rgb(var(--v-theme-background));
    }

    .input {
      position: relative;

      input {
        width: 15rem;
        height: 1.75rem;
        padding: 0.25rem 1.0625rem;
        outline: none;
        letter-spacing: 0.2px;

        &::placeholder {
          font-weight: 400;
          color: rgb(var(--v-theme-input));
        }
      }
      .tag {
        width: fit-content;
        position: absolute;
        top: 0;

        span {
          color: transparent;
        }
      }
    }
  }

  .cached-tags {
    .tag {
      border: 0.125rem solid rgb(var(--v-theme-surface));
    }
  }

  .tags,
  .cached-tags {
    display: flex;
    flex-direction: row;
    flex-wrap: wrap;

    .tag {
      height: 1.75rem;
      padding: 0.25rem 1rem;
      margin-bottom: 0.5rem;
      border-radius: 0.875rem;
      display: flex;
      flex-direction: row;
      align-items: center;
    }
  }
}

.tags-move, /* 对移动中的元素应用的过渡 */
.tags-enter-active,
.tags-leave-active {
  transition: all 0.5s ease;
}

.tags-enter-from,
.tags-leave-to {
  opacity: 0;
  transform: scale(0);
}

/* 确保将离开的元素从布局流中删除
  以便能够正确地计算移动的动画。 */
.tags-leave-active {
  position: absolute;
}
</style>
